package com.xiaomaoguai.fcp.pre.kepler.router.handler;

import com.xiaomaoguai.fcp.pre.kepler.router.async.AsyncInfo;
import com.xiaomaoguai.fcp.pre.kepler.router.async.RouterWorkPoolManager;
import com.xiaomaoguai.fcp.pre.kepler.router.exception.HandlerNotFoundException;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.enums.CallBack;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.enums.HandlerType;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.spi.HandlerManager;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.UrlManager;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.Serializable;
import java.util.List;

/**
 * router流程
 *
 * @author DH
 */
public class RouterInfo implements Serializable {

    /**
     * uid
     */
    private static final long serialVersionUID = 6895142129234378135L;

    /**
     * 执行序号*
     */
    private Integer order;

    /**
     * handlerName
     */
    private String name;

    /**
     * 分支
     */
    private List<Branch> branchList;

    /**
     * mock标识*
     */
    private String mock;

    /**
     * 当前handler是否需要获取锁 如果需要获取锁的话，这个字段不为空， 其中支持多个key以 ：拼接 支持aviator表达式，多个以 ,隔开
     */
    private String lockKey;

    /**
     * 当前handler是否需要解锁 如果需要获取锁的话，这个字段不为空， 其中支持多个key以 ：拼接 支持aviator表达式，多个以 ,隔开
     */
    private String unLockKey;

    /**
     * 异步信息
     */
    private AsyncInfo asyncInfo;

    /**
     * 是否异步
     */
    private boolean async = Boolean.FALSE;

    /**
     * 异步 rpc时生效
     * 异步串行执行责任链
     */
    private String callBack = CallBack.NO.name();

    /**
     * rpc 地址 默认为空时，配置指定url请求调用
     */
    private String rpcUrl;

    /**
     * url 通过appName对应的url填充
     */
    private String url;

    /**
     * 备注
     */
    private String memo;

    /**
     * handler执行策略
     */
    private String rule;


    /**
     * handler调用类型
     *
     * @see com.xiaomaoguai.fcp.pre.kepler.router.handler.enums.HandlerType
     */
    private String type = HandlerType.LOCAL.name();

    private HandlerInfo handlerInfo;

    public RouterInfo() {
    }

    public RouterInfo(String name) {
        this.name = name;
    }

    public RouterInfo(Integer order, String name) {
        this.order = order;
        this.name = name;
    }

    /**
     * 初始化router 添加线程池
     */
    public RouterInfo init() {
        if (asyncInfo != null) {
            RouterWorkPoolManager.addPool(asyncInfo);
            this.async = Boolean.TRUE;
        }
        if (CollectionUtils.isNotEmpty(branchList)) {
            for (Branch branch : branchList) {
                branch.init();
            }
        }
        return this;
    }

    public RouterInfo build() {
        // 填充handlerinfo
        if (StringUtils.isBlank(name)) {
            throw new HandlerNotFoundException("routerInfo.name is blank");
        } else {
            handlerInfo = HandlerManager.getHandlerInfo(name);
        }
        if (handlerInfo == null) {
            throw new HandlerNotFoundException(String.format("%s is not exist", name));
        }

        if (StringUtils.isBlank(handlerInfo.getApplication()) || !HandlerManager.isRPCHandler(name)) {
            this.type = HandlerType.LOCAL.name();
            this.rpcUrl = null;
        } else if (StringUtils.isNoneBlank(rpcUrl)) {
            // 填充rpcUrl 如果默认填写则是指定url请求
            this.type = HandlerType.RPC.name();
        } else if (HandlerManager.isRPCHandler(name)) {
            this.url = UrlManager.getUrl(handlerInfo.getApplication());
            this.type = HandlerType.RPC.name();
        }
        return this;
    }

    public String getRpcUrl() {
        return rpcUrl;
    }

    public void setRpcUrl(String rpcUrl) {
        this.rpcUrl = rpcUrl;
    }

    public boolean isAsync() {
        return async;
    }

    public void setAsync(boolean async) {
        this.async = async;
    }

    public AsyncInfo getAsyncInfo() {
        return asyncInfo;
    }

    public void setAsyncInfo(AsyncInfo asyncInfo) {
        this.asyncInfo = asyncInfo;
    }

    public String getMock() {
        return mock;
    }

    public void setMock(String mock) {
        this.mock = mock;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }

    public List<Branch> getBranchList() {
        return branchList;
    }

    public void setBranchList(List<Branch> branchList) {
        this.branchList = branchList;
    }

    public String getLockKey() {
        return lockKey;
    }

    public void setLockKey(String lockKey) {
        this.lockKey = lockKey;
    }

    public String getUnLockKey() {
        return unLockKey;
    }

    public void setUnLockKey(String unLockKey) {
        this.unLockKey = unLockKey;
    }

    public HandlerInfo getHandlerInfo() {
        return handlerInfo;
    }

    public void setHandlerInfo(HandlerInfo handlerInfo) {
        this.handlerInfo = handlerInfo;
    }

    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }

    public String getAsyncWorkPool() {
        return async ? asyncInfo.getAsyncWorkPool() : null;
    }

    /**
     * 获取appName 用于判断是否需要远程调用
     *
     * @return
     */
    public String appName() {
        if (handlerInfo != null) {
            return handlerInfo.getApplication();
        }
        return null;
    }

    /**
     * 匹配比较handlerType
     *
     * @param handlerType
     * @return
     */
    public boolean matchHandlerType(HandlerType handlerType) {
        return HandlerType.valueOf(type) == handlerType;
    }

    /**
     * 获取远程调用url
     *
     * @return
     */
    public String getUrl() {
        if (StringUtils.isNoneBlank(rpcUrl)) {
            return rpcUrl;
        }
        return url;
    }

    public String getCallBack() {
        return callBack;
    }

    public void setCallBack(String callBack) {
        this.callBack = callBack;
    }

    public boolean isCallBack() {
        return CallBack.valueOf(callBack) == CallBack.YES;
    }

    public String getRule() {
        return rule;
    }

    public void setRule(String rule) {
        this.rule = rule;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("order", order).append("name", name).append("branchList", branchList)
                .append("mock", mock).append("lockKey", lockKey).append("unLockKey", unLockKey)
                .append("asyncInfo", asyncInfo).append("async", async).append("rule", handlerInfo).append("memo", memo).append("type", type)
                .append("handlerInfo", handlerInfo).toString();
    }

}
